/*
 * Copyright 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.shaded.client.android.result;

import java.util.Vector;

import sfeir.ergosum.tools.Pair;

//import com.google.zxing.Result;

/**
 * Parses contact information formatted according to the VCard (2.1) format.
 * This is not a complete implementation but should parse information as
 * commonly encoded in 2D barcodes.
 * 
 * @author Sean Owen
 */
public class VCardResultParser extends ResultParser {

    protected VCardResultParser() {
    }

    // public static AddressBookParsedResult parse(Result result) {
    // String rawText = result.getText();
    // if (rawText == null || !rawText.startsWith("BEGIN:VCARD") ||
    // !rawText.endsWith("END:VCARD")) {
    // return null;
    // }
    // String[] names = matchVCardPrefixedField("FN", rawText, true);
    // if (names == null) {
    // // If no display names found, look for regular name fields and format
    // them
    // names = matchVCardPrefixedField("N", rawText, true);
    // formatNames(names);
    // }
    // String[] phoneNumbers = matchVCardPrefixedField("TEL", rawText, true);
    // String[] emails = matchVCardPrefixedField("EMAIL", rawText, true);
    // String note = matchSingleVCardPrefixedField("NOTE", rawText, false);
    // String address = matchSingleVCardPrefixedField("ADR", rawText, true);
    // address = formatAddress(address);
    // String org = matchSingleVCardPrefixedField("ORG", rawText, true);
    // String birthday = matchSingleVCardPrefixedField("BDAY", rawText, true);
    // if (birthday != null && !isStringOfDigits(birthday, 8)) {
    // return null;
    // }
    // String title = matchSingleVCardPrefixedField("TITLE", rawText, true);
    // String url = matchSingleVCardPrefixedField("URL", rawText, true);
    // return new AddressBookParsedResult(names, null, phoneNumbers, emails,
    // note, address, org,
    // birthday, title, url);
    // }
    @SuppressWarnings("unchecked")
    protected static Pair<String, String>[] matchVCardPrefixedField(
            String prefix, String rawText, boolean trim) {
        Vector matches = null;
        int i = 0;
        int max = rawText.length();
        while (i < max) {
            i = rawText.indexOf(prefix, i);
            if (i < 0) {
                break;
            }
            if (i > 0 && rawText.charAt(i - 1) != '\n') {
                // then this didn't start a new token, we matched in the middle
                // of something
                i++;
                continue;
            }
            i += prefix.length(); // Skip past this prefix we found to start
            if (rawText.charAt(i) != ':' && rawText.charAt(i) != ';') {
                continue;
            }
            int start = i;
            while (rawText.charAt(i) != ':') { // Skip until a colon
                i++;
            }
            String type = null;
            int itype = start;
            while (itype < i) {
                itype = rawText.indexOf("TYPE=", itype);
                if (itype > start && i > itype) {
                    itype += 5;
                    start = itype;
                    while (itype < i && ';' != rawText.charAt(itype))
                        itype++;
                    type = rawText.substring(start, itype);
                } else
                    break;
            }
            i++; // skip colon
            start = i; // Found the start of a match here
            i = rawText.indexOf((int) '\n', i); // Really, ends in \r\n
            if (i < 0) {
                // No terminating end character? uh, done. Set i such that loop
                // terminates and break
                i = max;
            } else if (i > start) {
                // found a match
                if (matches == null) {
                    matches = new Vector(3); // lazy init
                }
                String element = rawText.substring(start, i);
                if (trim) {
                    element = element.trim();
                }
                // FIX (TelHosting VCard generator)
                while (' ' == rawText.charAt(i + 1)) {
                    start = i + 2;
                    i = rawText.indexOf((int) '\n', i + 1);
                    String supp = rawText.substring(start, i);
                    element = element.concat(supp.trim());
                }
                // End fix
                matches.addElement(new Pair<String, String>(type, element));
                i++;
            } else {
                i++;
            }
        }
        if (matches == null || matches.isEmpty()) {
            return null;
        }
        return toPairArray(matches);
    }

    protected static Pair<String, String> matchSingleVCardPrefixedField(
            String prefix, String rawText, boolean trim) {
        Pair<String, String>[] values = matchVCardPrefixedField(prefix,
                rawText, trim);
        return values == null ? null : values[0];
    }

    protected static Pair<String, String> formatAddress(
            Pair<String, String> address) {
        if (address == null) {
            return null;
        }
        int length = address.getSecond().length();
        StringBuffer newAddress = new StringBuffer(length);
        for (int j = 0; j < length; j++) {
            char c = address.getSecond().charAt(j);
            if (c == ';') {
                newAddress.append(' ');
            } else {
                newAddress.append(c);
            }
        }
        return new Pair<String, String>(address.getFirst(), newAddress
                .toString().trim());
    }

    /**
     * Formats name fields of the form "Public;John;Q.;Reverend;III" into a form
     * like "Reverend John Q. Public III".
     * 
     * @param names
     *            name values to format, in place
     */
    protected static String[] formatNames(Pair<String, String>[] names) {
        if (names != null) {
            // for (int i = 0; i < names.length; i++) {
            String name = names[0].getSecond();
            String[] components = new String[5];
            int start = 0;
            int end;
            int componentIndex = 0;
            if (';' == name.charAt(0))
                name = name.substring(1);
            while ((end = name.indexOf(';', start)) > 0) {
                components[componentIndex] = name.substring(start, end);
                componentIndex++;
                start = end + 1;
            }
            components[componentIndex] = name.substring(start);

            StringBuffer newName = new StringBuffer();
            maybeAppendComponent(components, 3, newName);
            maybeAppendComponent(components, 1, newName);
            maybeAppendComponent(components, 2, newName);
            maybeAppendComponent(components, 0, newName);
            maybeAppendComponent(components, 4, newName);
            // names[i].setSecond(newName.toString().trim());
            return components;
            // }
        }
        return null;
    }

    private static void maybeAppendComponent(String[] components, int i,
            StringBuffer newName) {
        if (components[i] != null) {
            newName.append(' ');
            newName.append(components[i]);
        }
    }

}
